package cn.com.bluemoon.daps.standard.service.impl;

import cn.com.bluemoon.daps.common.constant.DapConstant;
import cn.com.bluemoon.daps.common.domain.BaseModel;
import cn.com.bluemoon.daps.common.domain.UserInfoHolder;
import cn.com.bluemoon.daps.common.enums.BmStatus;
import cn.com.bluemoon.daps.common.enums.StandardAuditStatus;
import cn.com.bluemoon.daps.common.exception.DapException;
import cn.com.bluemoon.daps.common.toolkit.BmAssetUtils;
import cn.com.bluemoon.daps.common.toolkit.TreeUtils;
import cn.com.bluemoon.daps.standard.entity.*;
import cn.com.bluemoon.daps.standard.mapper.DapStandardAuditVersionMainMapper;
import cn.com.bluemoon.daps.standard.mapper.DapStandardBasicMapper;
import cn.com.bluemoon.daps.standard.mapper.DapStandardIndexMapper;
import cn.com.bluemoon.daps.standard.service.*;
import cn.com.bluemoon.daps.standard.util.GsonExclusionField;
import cn.com.bluemoon.daps.standard.vo.BasicStandardAndDicVo;
import cn.com.bluemoon.daps.standard.vo.IndexStandardVo;
import cn.com.bluemoon.daps.standard.vo.StandardDataModifyVo;
import cn.com.bluemoon.daps.standard.vo.StandardListSearchVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.gson.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 数据标准的核心表，记录各标准的版本和审核状态 服务实现类
 * </p>
 *
 * @author admin
 * @since 2020-08-07
 */
@Slf4j
@Service
@Transactional(rollbackFor = {DapException.class, Exception.class})
public class DapStandardAuditVersionMainServiceImpl extends ServiceImpl<DapStandardAuditVersionMainMapper,
        DapStandardAuditVersionMain> implements DapStandardAuditVersionMainService {

    public static final Gson CUSTOM_GSON = new GsonBuilder()
            .setExclusionStrategies(new GsonExclusionFieldExclusionStrategy())
//            .registerTypeAdapter(LocalDateTime.class, new LocalDateAdapter())
            .create();

    @Resource
    private DapStandardBasicService standardBasicService;
    @Resource
    private DapStandardIndexService standardIndexService;

    @Resource
    private DapStandardDimService dimService;

    @Resource
    private DapStandardAuditVersionMainMapper auditVersionMainMapper;

    @Autowired
    private DapStandardVersionService standardVersionService;

    /**
     * 针对标准进行发布更新 标准字段信息
     * {@link BasePublishInfoOfStandard#setPublishNewest(Boolean)}
     */
    @Override
    public void updateStandardPublishInfo(String standardId, Integer standardType, Boolean isPublish, String standardUniqueId) {
        standardType = standardType == null ? 0 : standardType;
        BasePublishInfoOfStandard<?> standardIndex;
        if (standardType == 0) {
            standardIndex = standardBasicService.getById(standardId);
        } else {
            standardIndex = standardIndexService.getById(standardId);
        }
        if (Boolean.TRUE.equals(isPublish)) {
            BmAssetUtils.isFalse(Boolean.TRUE.equals(standardIndex.getPublishNewest()), "标准已发布无需重复发布");
            standardIndex.setPublishNewest(Boolean.TRUE);
            standardIndex.setPublishTime(LocalDateTime.now());
            // 针对多个版本的发布，下一个版本发布时，需要把之前的版本的publish_newest更新为空或者false
            updateStandardPublishInfoByParams(standardUniqueId, standardType);
        }
        if (StringUtils.isNotBlank(standardUniqueId)) {
            standardIndex.setStandardUniqueId(standardUniqueId);
        }
        standardIndex.insertOrUpdate();
    }

    /**
     * @param standardUniqueId 同一标准的唯一id
     * @param standardType     修改 字段publish_newest
     */
    private void updateStandardPublishInfoByParams(String standardUniqueId, Integer standardType) {
        if (standardType == null || standardType == 0) {
            standardBasicService.getBaseMapper(DapStandardBasicMapper.class).updatePublishNewestByStandardUniqueId(standardUniqueId, Boolean.FALSE);
        } else {
            standardIndexService.getBaseMapper(DapStandardIndexMapper.class).updatePublishNewestByStandardUniqueId(standardUniqueId, Boolean.FALSE);
        }
    }

    @Override
    public Optional<DapStandardAuditVersionMain> findOneByStandardIdAndStandardType(String standardId, Integer standardType) {
        @SuppressWarnings("unchecked")
        LambdaQueryWrapper<DapStandardAuditVersionMain> eq = Wrappers.lambdaQuery(new DapStandardAuditVersionMain())
                .eq(DapStandardAuditVersionMain::getStandardId, standardId)
                .eq(DapStandardAuditVersionMain::getBmStatus, BmStatus.ON)
                .eq(DapStandardAuditVersionMain::getStandardType, standardType)
                .last("limit 1")
                .orderByDesc(DapStandardAuditVersionMain::getVersion, DapStandardAuditVersionMain::getUpdateTime);
        DapStandardAuditVersionMain auditVersionMain = getOne(eq);
        return Optional.ofNullable(auditVersionMain);
    }

    /**
     * @param standardId     当前标准id
     * @param standardType   标准类型
     * @param auditStatus    转为
     * @param nextStandardId 若为已发布，指定对应的下一版本id
     */
    @Override
    public void auditChangeByStandardId(String standardId, Integer standardType,
                                        StandardAuditStatus auditStatus, Integer modifyType, String nextStandardId) {
        LambdaQueryWrapper<DapStandardAuditVersionMain> where = bmLambdaQuery()
                .eq(DapStandardAuditVersionMain::getStandardId, standardId);
        DapStandardAuditVersionMain auditVersionMain = getOne(where);
        String auditId;
        // 标准首次启动流程为空，自动生成初始流程
        if (auditVersionMain == null) {
            // 增加流程写入, 针对新增、修改、删除、进行版本控制
            DapStandardAuditVersionMain initAudit = new DapStandardAuditVersionMain();
            initAudit.setAuditStatus(StandardAuditStatus.草稿);
            initAudit.setStandardId(standardId);
            initAudit.setModifyType(1);
            initAudit.setStandardType(standardType);
            initAudit.setPid(null);
            initAudit.setVersion(1);
            String standardUniqueId = IdWorker.getIdStr();
            initAudit.setStandardUniqueId(standardUniqueId);
            save(initAudit);
            log.info("记录标准数据审核表id:{},的审批情况：{}", initAudit.getId(), initAudit.getAuditStatus());
            // 更新标准id
            updateStandardPublishInfo(standardId, standardType, Boolean.FALSE, standardUniqueId);
            auditId = initAudit.getId();
        } else {
            auditId = auditVersionMain.getId();
        }
        auditChangeStatusById(auditId, auditStatus, modifyType, nextStandardId);
    }

    /**
     * 针对流程id 更新流程状态
     *
     * @param auditId           当前版的流程id 注意与参数targetAuditStatus差异（当前与期望状态）
     * @param targetAuditStatus 目标状态
     * @param modifyTypeDefine  定义变更类型，提供给流程通过（变更类型{@link DapStandardAuditVersionMain#getModifyType()}和变更状态 {@link DapStandardAuditVersionMain#getAuditStatus()}）
     *                          来指定流程的具体变更类型
     * @param nextStandardId    针对针对{@link StandardAuditStatus#已发布}进行编辑的情况，传入该参数进行启动新的流程（下一个版本）
     */
    private String auditChangeStatusById(String auditId,
                                         StandardAuditStatus targetAuditStatus,
                                         Integer modifyTypeDefine,
                                         String nextStandardId) {
        DapStandardAuditVersionMain standardAuditVersionMain = getByIdAsset(auditId, "审批流程不存在，无法发起审批");
        // 提供消费流程数据（当前流程状态->转为targetAuditStatus & 调整变更类型和更新标准状态
        Consumer<Void> consumer = processHandler(targetAuditStatus, modifyTypeDefine, standardAuditVersionMain);
        /*
        源数据状态 源审批状态
         */
        StandardAuditStatus sourceAuditStatus = standardAuditVersionMain.getAuditStatus();
        if (sourceAuditStatus.equals(targetAuditStatus)) {
            log.warn("源审批状态[{}]与目标状态[{}]一致，不进行流程业务处理", sourceAuditStatus, targetAuditStatus);
            return null;
        }
        switch (sourceAuditStatus) {
            case 草稿:
                /**
                 * {@link DapConstant.VersionMark#STANDARD_MODIFY_REVERT}
                 * 可以理解为把流程中的新版本进行删除，本方法只处理流程状态表，不对具体的标准数据进行删除，故只解除标准和流程的关联
                 * 若要删除对应标准，可在处理完本方法后进行进一步处理。
                 * 草稿动作，可以放行：待审批、撤销、不通过
                 */
                if (targetAuditStatus == null ||
                        StandardAuditStatus.待审批.equals(targetAuditStatus) ||
                        StandardAuditStatus.撤销.equals(targetAuditStatus) ||
                        StandardAuditStatus.不通过.equals(targetAuditStatus)) {
                    consumer.accept(null);
                } else {
                    throw new DapException("标准状态[" + sourceAuditStatus + "]不可转为状态[" + targetAuditStatus + "]");
                }
                break;
            case 通过:
            case 不通过:
                /**
                 * {@link DapConstant.VersionMark#STANDARD_MODIFY_REVERT}
                 * 可以理解为把流程中的新版本进行删除，本方法只处理流程状态表，不对具体的标准数据进行删除，故只解除标准和流程的关联
                 * 若要删除对应标准，可在处理完本方法后进行进一步处理。
                 * 不通过动作，可以放行：待审批、撤销
                 */
                if (targetAuditStatus == null || StandardAuditStatus.待审批.equals(targetAuditStatus) ||
                        StandardAuditStatus.撤销.equals(targetAuditStatus)) {
                    consumer.accept(null);
                } else {
                    throw new DapException("标准状态[" + sourceAuditStatus + "]不可转为状态[" + targetAuditStatus + "]");
                }
                break;
            case 待审批:
                /**
                 * {@link DapConstant.VersionMark#STANDARD_MODIFY_REVERT}
                 * 可以理解为把流程中的新版本进行删除，本方法只处理流程状态表，不对具体的标准数据进行删除，故只解除标准和流程的关联
                 * 若要删除对应标准，可在处理完本方法后进行进一步处理。
                 * 去除放行 撤销动作
                 */
                if (targetAuditStatus == null ||
                        StandardAuditStatus.已发布.equals(targetAuditStatus) ||
                        StandardAuditStatus.不通过.equals(targetAuditStatus) ||
                        StandardAuditStatus.通过.equals(targetAuditStatus)) {
                    consumer.accept(null);
                } else {
                    throw new DapException("标准状态[" + sourceAuditStatus + "]不可转为状态[" + targetAuditStatus + "]");
                }
                break;
            case 已发布:
                if (StandardAuditStatus.草稿.equals(targetAuditStatus) ||
                        StandardAuditStatus.新版本.equals(targetAuditStatus)) {
                    // 已发布进行草稿 标识为新版本的产生 返回
                    DapStandardAuditVersionMain auditVersionMainNewV = new DapStandardAuditVersionMain();
                    auditVersionMainNewV.setAuditStatus(StandardAuditStatus.草稿);
                    nextStandardId = Optional.ofNullable(nextStandardId).orElseThrow(() -> new DapException("针对已发布的版本进行编辑保存，需要指定下一个版本的标准id"));
                    auditVersionMainNewV.setStandardId(nextStandardId);
                    auditVersionMainNewV.setModifyType(modifyTypeDefine);
                    auditVersionMainNewV.setStandardType(standardAuditVersionMain.getStandardType());
                    auditVersionMainNewV.setPid(standardAuditVersionMain.getId());
                    int version = standardAuditVersionMain.getVersion() == null ? 1 : standardAuditVersionMain.getVersion();
                    auditVersionMainNewV.setVersion(++version);
                    auditVersionMainNewV.setStandardUniqueId(standardAuditVersionMain.getStandardUniqueId());
                    auditVersionMainNewV.insertOrUpdate();
                    log.info("记录标准数据审核表id:{},对应标准id:{},的审批情况：{}", auditVersionMainNewV.getId(), nextStandardId, auditVersionMainNewV.getAuditStatus());
                    return nextStandardId;
                } else {
                    throw new DapException("标准状态[" + sourceAuditStatus + "]不可转为状态[" + targetAuditStatus + "]");
                }
            default:
                throw new DapException("标准状态[" + sourceAuditStatus + "]不可转为状态[" + targetAuditStatus + "]");
        }
        return null;
    }

    /**
     * 针对
     */
    private Consumer<Void> processHandler(StandardAuditStatus targetAuditStatus,
                                          Integer modifyTypeDefine,
                                          DapStandardAuditVersionMain standardAuditVersionMain) {
        return v -> {
            // 结合动作进行指定变更类型，// 为空表示，当前动作不进行变更调整
            if (modifyTypeDefine != null) {
                standardAuditVersionMain.setModifyType(modifyTypeDefine);
            }
            // 为空表示，当前动作不进行状态调整
            if (targetAuditStatus != null) {
                if (StandardAuditStatus.撤销.equals(targetAuditStatus)) {
                    /**
                     * {@link DapConstant.VersionMark#STANDARD_MODIFY_REVERT}
                     * 可以理解为把流程中的新版本进行删除，本方法只处理流程状态表，不对具体的标准数据进行删除，故只解除标准和流程的关联
                     * 若要删除对应标准，可在处理完本方法后进行进一步处理。 同时删除对应【当前流程的标准数据】
                     */
                    standardAuditVersionMain.setBmStatus(BmStatus.DELETE);
                    deleteStandard(standardAuditVersionMain.getStandardId(), standardAuditVersionMain.getStandardType(), true);
                } else if (StandardAuditStatus.通过.equals(targetAuditStatus)) {
                    // 更新标准id的 字段为已发布+发布时间
                    updateStandardPublishInfo(standardAuditVersionMain.getStandardId(), standardAuditVersionMain.getStandardType(),
                            Boolean.TRUE, standardAuditVersionMain.getStandardUniqueId());
                    standardAuditVersionMain.setAuditStatus(StandardAuditStatus.已发布);
                } else if (StandardAuditStatus.不通过.equals(targetAuditStatus)) {
                    standardAuditVersionMain.setAuditStatus(StandardAuditStatus.不通过);
                } else {
                    standardAuditVersionMain.setAuditStatus(targetAuditStatus);
                }
            }
            standardAuditVersionMain.setUpdateTime(LocalDateTime.now());
            saveOrUpdate(standardAuditVersionMain);
//            standardAuditVersionMain.insertOrUpdate();
            // 变更类型为3（删除）+变更状态为通过 则进行删除标准数据
            if (modifyTypeDefine != null && modifyTypeDefine == 3 && StandardAuditStatus.通过.equals(targetAuditStatus)) {
                deleteAllVersionStandard(standardAuditVersionMain.getStandardId(), standardAuditVersionMain.getStandardType(), true);
                log.info("变更类型为3（删除）+变更状态为通过 则进行删除标准数据");
            }
        };
    }

    /**
     * 根据类型处理对应表
     *
     * @param standardId   b
     * @param standardType type
     * @param isLogic      logic删除
     */
    @Override
    @Transactional
    public void deleteAllVersionStandard(String standardId, Integer standardType, boolean isLogic) {
        if (standardType == null || standardType == 0) {
            standardBasicService.deleteStandardBasicAndDic(standardId, isLogic);
        } else {
            standardIndexService.deleteStandardIndex(standardId, isLogic);
        }
    }

    /**
     * 根据类型处理对应表
     *
     * @param standardId   b
     * @param standardType type
     * @param isLogic      logic删除
     */
    @Override
    public void deleteStandard(String standardId, Integer standardType, boolean isLogic) {
        if (standardType == null || standardType == 0) {
            standardBasicService.deleteSingleStandardBasicAndDic(standardId, isLogic);
        } else {
            standardIndexService.deleteSingleStandardIndex(standardId, isLogic);
        }
    }

    @Override
    public void auditChangeStatusByAuditId(String auditId, StandardAuditStatus auditStatus, Integer modifyType) {
        auditChangeStatusById(auditId, auditStatus, modifyType, null);
    }

    /**
     * 获取基础标准或者指标标准列表数据
     *
     * @param standardListSearchVo 是否为审核列表请求 默认为false
     */
    @Override
    public IPage<StandardDataModifyVo> modifyOrAuditListOfStandard(StandardListSearchVo<?> standardListSearchVo,
                                                                   Boolean auditPageListReq) {
        //noinspection AliControlFlowStatementWithoutBraces
        if (Boolean.TRUE.equals(auditPageListReq)) {
            standardListSearchVo.setAuditPageListReq(Boolean.TRUE);
        }
        IPage<DapStandardAuditVersionMain> iPage;
        if (standardListSearchVo.getStandardType() == null || standardListSearchVo.getStandardType() == 0) {
            standardListSearchVo.setStandardType(0);
            iPage = getBaseMapper().selectPageModifiesByStandardBasic(standardListSearchVo.toMpPage(), standardListSearchVo);
        } else {
            iPage = getBaseMapper().selectPageModifiesByStandardIndex(standardListSearchVo.toMpPage(), standardListSearchVo);
        }
        return iPage.convert(new ModifyOrAuditFunction(standardListSearchVo));
    }

    @Override
    public IPage<StandardDataModifyVo> modifyOrAuditLogicPageOfStandard(StandardListSearchVo<?> searchVo, Boolean auditListPageRequest) {
        //noinspection AliControlFlowStatementWithoutBraces
        if (Boolean.TRUE.equals(auditListPageRequest)) {
            searchVo.setAuditPageListReq(Boolean.TRUE);
        }
        List<DapStandardAuditVersionMain> auditVersionMains;
        if (searchVo.getStandardType() == null || searchVo.getStandardType() == 0) {
            searchVo.setStandardType(0);
            auditVersionMains = auditVersionMainMapper.selectPageModifiesByStandardBasic(searchVo);
        } else {
            auditVersionMains = auditVersionMainMapper.selectPageModifiesByStandardIndex(searchVo);
        }
        List<DapStandardAuditVersionMain> trees = TreeUtils.createTrees(auditVersionMains, "id", "pid",
                "children", null, null);
        long offset = (searchVo.getCurrent() <= 0 ? 1 : searchVo.getCurrent()) - 1;
        long limit = searchVo.getPageSize();
        List<DapStandardAuditVersionMain> logicPageContent = trees.stream().skip(offset).limit(limit).collect(Collectors.toList());
        Page<DapStandardAuditVersionMain> page = new Page<>();
        return page.setRecords(logicPageContent).setCurrent(offset + 1).setSize(limit).setTotal(trees.size())
                .convert(new ModifyOrAuditFunction(searchVo));
    }

    /**
     * 根据唯一id获取审批表中的有效数据都处于已发布状态，若是返回true
     */
    @Override
    public boolean checkStandardPublishedByStandardUniqueId(String standardUniqueId) {
        LambdaQueryWrapper<DapStandardAuditVersionMain> where = Wrappers.<DapStandardAuditVersionMain>lambdaQuery().eq(DapStandardAuditVersionMain::getStandardUniqueId, standardUniqueId).eq(BaseModel::getBmStatus, BmStatus.ON);
        return list(where).stream().allMatch(d -> StandardAuditStatus.已发布.equals(d.getAuditStatus()));
    }

    /**
     * 断言判断标准对应的审批数据必须都为已发布
     * 目前用于删除标准数据中的强制约束
     */
    @Override
    public void assetStandardPublished(String standardUniqueId,
                                       String message) {
        boolean allPublish = checkStandardPublishedByStandardUniqueId(standardUniqueId);
        BmAssetUtils.isTrue(allPublish, StringUtils.isNotBlank(message) ? message : "标准数据存在未发布版本，不可删除");
    }

    /**
     * 标准id获取标准唯一id然后进行判断都为已发布
     */
    @Override
    public void assetStandardPublishedByStandardId(String standardId, String message) {
        LambdaQueryWrapper<DapStandardAuditVersionMain> where = Wrappers.<DapStandardAuditVersionMain>lambdaQuery().eq(DapStandardAuditVersionMain::getStandardId, standardId).eq(BaseModel::getBmStatus, BmStatus.ON);
        where.last("limit 1");
        String standardUniqueId = Optional.ofNullable(getOne(where)).orElseThrow(() -> new DapException("获取标准数据失败")).getStandardUniqueId();
        // javax.validation.ConstraintDeclarationException: HV000151: A method overriding another method must not redefine the parameter constraint configuration,
        assetStandardPublished(standardUniqueId, message);
    }

    @Override
    public List<DapStandardAuditVersionMain> findByStandardUniqueId(String standardUniqueId) {
        LambdaQueryWrapper<DapStandardAuditVersionMain> eq = bmLambdaQuery().eq(DapStandardAuditVersionMain::getStandardUniqueId, standardUniqueId)
                .orderByDesc(DapStandardAuditVersionMain::getCreateTime);
        return list(eq);
    }

    @Override
    public void saveStandardVersion(List<String> auditIds, String modifyDesc, UserInfoHolder.UserInfo userInfo) {
        Collection<DapStandardAuditVersionMain> auditVersionMains = listByIds(auditIds);
        List<DapStandardVersion> versions = auditVersionMains.stream().map(a -> {
            DapStandardVersion version = new DapStandardVersion();
            version.setModifyDesc(modifyDesc);
            version.setModifyTime(a.getUpdateTime());
            version.setModifyType(a.getModifyType());
            version.setStandardUniqueId(a.getStandardUniqueId());
            version.setStandardType(a.getStandardType());
            version.setAuditProcessId(a.getId());
            if (a.getStandardType() == 1) {
                DapStandardIndex d = standardIndexService.getById(a.getStandardId());
                IndexStandardVo indexStandardVo = new IndexStandardVo(d);
                standardIndexService.transferDicInfo(d, indexStandardVo);
                // 翻译relatedIndex 日期转为str
                if (indexStandardVo.getRelatedIndex() != null && indexStandardVo.getRelatedIndex().split(",").length > 0) {
                    List<String> stdUniqueIds = Arrays.stream(indexStandardVo.getRelatedIndex().split(",")).distinct().collect(Collectors.toList());
                    List<DapStandardIndex> indices = standardIndexService.list(
                            standardIndexService.bmLambdaQuery().eq(DapStandardIndex::getPublishNewest, true)
                                    .in(DapStandardIndex::getStandardUniqueId, stdUniqueIds));
                    String indexNames = indices.stream().map(DapStandardIndex::getIndexChinName).collect(Collectors.joining(","));
                    indexStandardVo.setRelatedIndexNames(indexNames);
                }
                if (indexStandardVo.getAssociationDimension() != null && indexStandardVo.getAssociationDimension().split(",").length > 0) {
                    Collection<DapStandardDim> dims = dimService.listByIds(Arrays.stream(indexStandardVo.getAssociationDimension().split(",")).collect(Collectors.toList()));
                    indexStandardVo.setAssociationDimensionNames(dims.stream().map(DapStandardDim::getCodeName).collect(Collectors.joining(",")));
                }
                indexStandardVo.setIndexTypeName(IndexStandardVo.indexTypeToName(indexStandardVo.getIndexType()));
                indexStandardVo.setCreateBy(userInfo.getUserName());
                indexStandardVo.setUpdateBy(userInfo.getUserName());
                version.setStandardJson(CUSTOM_GSON.toJson(indexStandardVo));
            } else if (a.getStandardType() == 0) {
                DapStandardBasic b = standardBasicService.getById(a.getStandardId());
                BasicStandardAndDicVo basicStandardVo = new BasicStandardAndDicVo(b);
                standardBasicService.transferDicInfo(b, basicStandardVo);
                version.setStandardJson(CUSTOM_GSON.toJson(basicStandardVo));
                basicStandardVo.setCreateBy(userInfo.getUserName());
                basicStandardVo.setUpdateBy(userInfo.getUserName());
            }
            return version;
        }).collect(Collectors.toList());
        standardVersionService.saveBatch(versions);
    }

    private static class LocalDateAdapter implements JsonSerializer<LocalDateTime> {
        @Override
        public JsonElement serialize(LocalDateTime localDateTime, java.lang.reflect.Type typeOfSrc, JsonSerializationContext context) {
            return new JsonPrimitive(localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }
    }

    private static class GsonExclusionFieldExclusionStrategy implements ExclusionStrategy {
        public boolean shouldSkipClass(Class<?> clazz) {
            return clazz.getAnnotation(GsonExclusionField.class) != null;
        }

        public boolean shouldSkipField(FieldAttributes f) {
            return f.getAnnotation(GsonExclusionField.class) != null;
        }
    }

    /**
     * 实体转为vo
     */
    public static class ModifyOrAuditFunction implements Function<DapStandardAuditVersionMain, StandardDataModifyVo> {
        private final StandardListSearchVo<?> searchVo;
        private final Boolean treePage;

        public ModifyOrAuditFunction(StandardListSearchVo<?> searchVo) {
            this.searchVo = searchVo;
            this.treePage = searchVo.getTreePage();
        }

        /**
         * Applies this function to the given argument.
         *
         * @param d the function argument
         * @return the function result
         */
        @Override
        public StandardDataModifyVo apply(DapStandardAuditVersionMain d) {
            if (Boolean.FALSE.equals(treePage)) {
                return getStandardDataModifyVoByModel(d);
            }
            return d != null ? reverse(d) : null;
        }

        /**
         * 递归把tree节点DapStandardAuditVersionMain 转为 StandardDataModifyVo
         */
        public StandardDataModifyVo reverse(DapStandardAuditVersionMain d) {
            List<DapStandardAuditVersionMain> children = d.getChildren();
            if (children != null && !children.isEmpty()) {
                StandardDataModifyVo vo = getStandardDataModifyVoByModel(d);
                List<StandardDataModifyVo> voChild = Lists.newArrayList();
                for (DapStandardAuditVersionMain d2 : children) {
                    voChild.add(getStandardDataModifyVoByModel(d2));
                    reverse(d2);
                }
                vo.setChildren(voChild);
                return vo;
            } else {
                return getStandardDataModifyVoByModel(d);
            }
        }

        private StandardDataModifyVo getStandardDataModifyVoByModel(DapStandardAuditVersionMain d) {
            StandardDataModifyVo standardDataModifyVo = new StandardDataModifyVo();
            BasicStandardAndDicVo v = d.getBasicStandardAndDicVo();
            standardDataModifyVo.setStandardId(d.getStandardId());
            if (v != null) {
                standardDataModifyVo.setCategory1(v.getFirstCategory());
                standardDataModifyVo.setCategory1Name(v.getFirstCategoryName());
                standardDataModifyVo.setCategory2(v.getSecondCategory());
                standardDataModifyVo.setCategory2Name(v.getSecondCategoryName());
                standardDataModifyVo.setCategory3(v.getThirdCategory());
                standardDataModifyVo.setCategory3Name(v.getThirdCategoryName());
                standardDataModifyVo.setTopicName(v.getTopicName());
                standardDataModifyVo.setTopicId(v.getTopicId());
                standardDataModifyVo.setStandardName(v.getName());
                standardDataModifyVo.setStandardEngName(v.getEngName());
                standardDataModifyVo.setStandardId(Optional.ofNullable(standardDataModifyVo.getStandardId()).orElse(v.getId()));
                standardDataModifyVo.setPublishNewest(Optional.ofNullable(v.getPublishNewest()).orElse(Boolean.FALSE));
                standardDataModifyVo.setPublishTime(Optional.ofNullable(v.getPublishTime()).orElse(null));
            }
            IndexStandardVo indexStandardVo = d.getStandardIndexVo();
            if (indexStandardVo != null && 1 == searchVo.getStandardType()) {
                standardDataModifyVo.setCategory1(indexStandardVo.getPrimarySort());
                standardDataModifyVo.setCategory1Name(indexStandardVo.getFirstCategoryName());
                standardDataModifyVo.setCategory2(indexStandardVo.getSecondarySort());
                standardDataModifyVo.setCategory2Name(indexStandardVo.getSecondCategoryName());
                standardDataModifyVo.setCategory3(indexStandardVo.getThirdSort());
                standardDataModifyVo.setCategory3Name(indexStandardVo.getThirdCategoryName());
                standardDataModifyVo.setTopicName(indexStandardVo.getTopicName());
                standardDataModifyVo.setTopicId(indexStandardVo.getTheme());
                standardDataModifyVo.setStandardName(indexStandardVo.getIndexChinName());
                standardDataModifyVo.setStandardEngName(indexStandardVo.getIndexEngName());
//                standardDataModifyVo.setStandardId(indexStandardVo.getId());
                standardDataModifyVo.setStandardId(Optional.ofNullable(standardDataModifyVo.getStandardId()).orElse(indexStandardVo.getId()));
                standardDataModifyVo.setPublishNewest(Optional.ofNullable(indexStandardVo.getPublishNewest()).orElse(Boolean.FALSE));
                standardDataModifyVo.setPublishTime(Optional.ofNullable(indexStandardVo.getPublishTime()).orElse(null));
            }
            standardDataModifyVo.setVersion(d.getVersion());
            standardDataModifyVo.setOperator(d.getUpdateBy());
            standardDataModifyVo.setCreator(d.getCreateBy());
            standardDataModifyVo.setProcessId(d.getId());
            standardDataModifyVo.setStandardUniqueId(d.getStandardUniqueId());
            standardDataModifyVo.setStandardType(d.getStandardType());
            standardDataModifyVo.setModifyStatus(d.getAuditStatus());
            standardDataModifyVo.setModifyTime(d.getUpdateTime());
            standardDataModifyVo.setModifyType(d.getModifyType());
            standardDataModifyVo.setTreeTitle(standardDataModifyVo.getTreeTitleContent());
            return standardDataModifyVo;
        }
    }
}
